#include <stdlib.h>

#include "ecb/benchmarks/cec10/CecBenchmark.h"
#include "ecb/benchmarks/cec10/F01.h"
#include "ecb/benchmarks/cec10/F02.h"
#include "ecb/benchmarks/cec10/F03.h"
#include "ecb/benchmarks/cec10/F04.h"
#include "ecb/benchmarks/cec10/F05.h"
#include "ecb/benchmarks/cec10/F06.h"
#include "ecb/benchmarks/cec10/F07.h"
#include "ecb/benchmarks/cec10/F08.h"
#include "ecb/benchmarks/cec10/F09.h"
#include "ecb/benchmarks/cec10/F10.h"
#include "ecb/benchmarks/cec10/F11.h"
#include "ecb/benchmarks/cec10/F12.h"
#include "ecb/benchmarks/cec10/F13.h"
#include "ecb/benchmarks/cec10/F14.h"
#include "ecb/benchmarks/cec10/F15.h"
#include "ecb/benchmarks/cec10/F16.h"
#include "ecb/benchmarks/cec10/F17.h"
#include "ecb/benchmarks/cec10/F18.h"
#include "ecb/benchmarks/cec10/F19.h"
#include "ecb/benchmarks/cec10/F20.h"
#include "ecb/base/Math.h"

#include "ecb/definitions.h"

#include <fstream>
#include <sstream>
#include <iomanip>


namespace ecb {
    namespace cec10 {
        //K. Tang, Xiaodong Li, P. N. Suganthan, Z. Yang and T. Weise,
        //Benchmark Functions for the CEC'2010 Special Session and Competition on Large Scale Global Optimization,
        //Technical Report, Nature Inspired Computation and Applications Laboratory, USTC, China,
        //http://nical.ustc.edu.cn/cec10ss.php

        CecBenchmark::CecBenchmark(int dimensions, int mValue)
        : Benchmark("cec10"), _dimensions(dimensions), _mValue(mValue) {
                addProblem(new F01(dimensions));
                addProblem(new F02(dimensions));
                addProblem(new F03(dimensions));
                addProblem(new F04(dimensions, mValue));
                addProblem(new F05(dimensions, mValue));
                addProblem(new F06(dimensions, mValue));
                addProblem(new F07(dimensions, mValue));
                addProblem(new F08(dimensions, mValue));
                addProblem(new F09(dimensions, mValue));
                addProblem(new F10(dimensions, mValue));
                addProblem(new F11(dimensions, mValue));
                addProblem(new F12(dimensions, mValue));
                addProblem(new F13(dimensions, mValue));
                addProblem(new F14(dimensions, mValue));
                addProblem(new F15(dimensions, mValue));
                addProblem(new F16(dimensions, mValue));
                addProblem(new F17(dimensions, mValue));
                addProblem(new F18(dimensions, mValue));
                addProblem(new F19(dimensions, mValue));
                addProblem(new F20(dimensions, mValue));
        }

        int CecBenchmark::dimensions() const {
            return this->_dimensions;
        }

        int CecBenchmark::mValue() const {
            return this->_mValue;
        }

        void CecBenchmark::Test() {
            int dimensions = 1000;
            int mvalue = 50;
            CecBenchmark cec(dimensions, mvalue);

            CecRandom* random = new CecRandom(99l);
            std::vector<scalar> x;
            for (int i = 0; i < dimensions; ++i) {
                x.push_back(random->nextScalar());
            }

            std::stringstream ss;

            for (int i = 0; i < cec.numberOfProblems(); ++i) {
                ss << "F" << (i + 1) << "(x) = " << cec.getProblem(i)->f(x) << "\n";
            }
            ECB_LOG(ss.str());

        }

        void CecBenchmark::Compare(const std::string& inFilepath) {
            //Input file model: Seed\s[Functions\s]^20

            std::vector<std::pair<long, std::vector<scalar> > > fromJava;

            std::string line;
            std::ifstream inFile(inFilepath.c_str());
            if (inFile.is_open()) {
                while (inFile.good()) {
                    getline(inFile, line);
                    if (line.empty()) {
                        continue;
                    }
                    std::stringstream ss(line);
                    std::string token;

                    std::pair<long, std::vector<scalar> > run;
                    ss >> token;
                    run.first = atol(token.c_str());

                    while (ss >> token) {
                        run.second.push_back(atof(token.c_str()));
                    }
                    fromJava.push_back(run);
                }
            }
            inFile.close();

            int dimensions = 1000;
            int mvalue = 50;

            CecBenchmark cec(dimensions, mvalue);

            for (size_t ithRun = 0; ithRun < fromJava.size(); ++ithRun) {
                std::pair<long, std::vector<scalar> > run = fromJava[ithRun];
                CecRandom random(run.first);

                std::vector<scalar> baseX;
                for (int ithDimension = 0; ithDimension < dimensions; ++ithDimension) {
                    baseX.push_back(random.nextScalar());
                }

                std::vector<scalar> fx;
                for (int ithProblem = 0; ithProblem < cec.numberOfProblems(); ++ithProblem) {
                    Problem* problem = cec.getProblem(ithProblem);
                    std::vector<scalar> x;
                    for (int ithDimension = 0; ithDimension < dimensions; ++ithDimension) {
                        x.push_back(ecb::Math::Scale<scalar > (baseX[ithDimension], 0, 1,
                                problem->properties()->getMinimum(),
                                problem->properties()->getMaximum()));
                    }
                    fx.push_back(problem->f(x));
                }
                ECB_LOG("Seed " << run.first);
                for (int ithProblem = 0; ithProblem < cec.numberOfProblems(); ++ithProblem) {
                    ECB_LOGP("Fj" << (ithProblem + 1) << " = " << run.second[ithProblem] << "\t"
                            << "F" << (ithProblem + 1) << " = " << fx[ithProblem] << "\t"
                            << "D = " << run.second[ithProblem] - fx[ithProblem]);
                }


            }


        }

    }
}
